// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraGameMode.h"
#include "AssetRegistry/AssetData.h"
#include "Engine/GameInstance.h"
#include "Engine/World.h"
#include "LyraLogChannels.h"
#include "Misc/CommandLine.h"
#include "System/LyraAssetManager.h"
#include "LyraGameState.h"
#include "System/LyraGameSession.h"
#include "Player/LyraPlayerController.h"
#include "Player/LyraPlayerBotController.h"
#include "Player/LyraPlayerState.h"
#include "Character/LyraCharacter.h"
#include "UI/LyraHUD.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "Character/LyraPawnData.h"
#include "GameModes/LyraWorldSettings.h"
#include "GameModes/LyraExperienceDefinition.h"
#include "GameModes/LyraExperienceManagerComponent.h"
#include "GameModes/LyraUserFacingExperienceDefinition.h"
#include "Kismet/GameplayStatics.h"
#include "Development/LyraDeveloperSettings.h"
#include "Player/LyraPlayerSpawningManagerComponent.h"
#include "CommonUserSubsystem.h"
#include "CommonSessionSubsystem.h"
#include "TimerManager.h"
#include "GameMapsSettings.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraGameMode)

/**
 * 构造函数，设置默认类
 */
ALyraGameMode::ALyraGameMode(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	GameStateClass = ALyraGameState::StaticClass(); // 游戏状态类
	GameSessionClass = ALyraGameSession::StaticClass(); // 游戏会话类
	PlayerControllerClass = ALyraPlayerController::StaticClass(); // 玩家控制器类
	ReplaySpectatorPlayerControllerClass = ALyraReplayPlayerController::StaticClass(); // 回放观察者玩家控制器类
	PlayerStateClass = ALyraPlayerState::StaticClass(); // 玩家状态类
	DefaultPawnClass = ALyraCharacter::StaticClass(); // 默认Pawn类
	HUDClass = ALyraHUD::StaticClass(); // HUD类
}

/**
 * 获取控制器的Pawn数据
 * @param InController 控制器
 * @return Pawn数据
 */
const ULyraPawnData* ALyraGameMode::GetPawnDataForController(const AController* InController) const
{
	// 查看玩家状态是否已设置Pawn数据
	if (InController != nullptr) // 确保控制器有效
	{
		if (const ALyraPlayerState* LyraPS = InController->GetPlayerState<ALyraPlayerState>()) // 获取Lyra玩家状态
		{
			if (const ULyraPawnData* PawnData = LyraPS->GetPawnData<ULyraPawnData>()) // 获取Pawn数据
			{
				return PawnData; // 返回Pawn数据
			}
		}
	}

	// 如果没有，回退到当前经验的默认值
	check(GameState); // 确保游戏状态有效
	ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
	check(ExperienceComponent); // 确保组件有效

	if (ExperienceComponent->IsExperienceLoaded()) // 如果经验已加载
	{
		const ULyraExperienceDefinition* Experience = ExperienceComponent->GetCurrentExperienceChecked(); // 获取当前经验
		if (Experience->DefaultPawnData != nullptr) // 如果经验有默认Pawn数据
		{
			return Experience->DefaultPawnData; // 返回经验的默认Pawn数据
		}

		// 经验已加载但仍然没有Pawn数据，暂时回退到默认值
		return ULyraAssetManager::Get().GetDefaultPawnData(); // 返回资源管理器的默认Pawn数据
	}

	// 经验尚未加载，因此没有Pawn数据可用
	return nullptr; // 返回空
}

/**
 * 初始化游戏
 * @param MapName 地图名称
 * @param Options 选项字符串
 * @param ErrorMessage 错误消息
 */
void ALyraGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
	Super::InitGame(MapName, Options, ErrorMessage); // 调用父类

	// 等待下一帧以给初始化启动设置的时间
	GetWorld()->GetTimerManager().SetTimerForNextTick(this, &ThisClass::HandleMatchAssignmentIfNotExpectingOne); // 设置下一帧的计时器
}

/**
 * 处理匹配分配（如果不期望）
 */
void ALyraGameMode::HandleMatchAssignmentIfNotExpectingOne()
{
	FPrimaryAssetId ExperienceId; // 经验ID
	FString ExperienceIdSource; // 经验ID来源

	// 优先级顺序（最高者获胜）
	//  - 匹配分配（如果存在）
	//  - URL选项覆盖
	//  - 开发者设置（仅PIE）
	//  - 命令行覆盖
	//  - 世界设置
	//  - 专用服务器
	//  - 默认经验

	UWorld* World = GetWorld(); // 获取世界

	if (!ExperienceId.IsValid() && UGameplayStatics::HasOption(OptionsString, TEXT("Experience"))) // 如果经验ID无效且选项中有Experience
	{
		const FString ExperienceFromOptions = UGameplayStatics::ParseOption(OptionsString, TEXT("Experience")); // 从选项解析经验
		ExperienceId = FPrimaryAssetId(FPrimaryAssetType(ULyraExperienceDefinition::StaticClass()->GetFName()), FName(*ExperienceFromOptions)); // 创建经验ID
		ExperienceIdSource = TEXT("OptionsString"); // 设置来源为选项字符串
	}

	if (!ExperienceId.IsValid() && World->IsPlayInEditor()) // 如果经验ID无效且在PIE中
	{
		ExperienceId = GetDefault<ULyraDeveloperSettings>()->ExperienceOverride; // 获取开发者设置的经验覆盖
		ExperienceIdSource = TEXT("DeveloperSettings"); // 设置来源为开发者设置
	}

	// 查看命令行是否要设置经验
	if (!ExperienceId.IsValid()) // 如果经验ID无效
	{
		FString ExperienceFromCommandLine; // 命令行经验
		if (FParse::Value(FCommandLine::Get(), TEXT("Experience="), ExperienceFromCommandLine)) // 从命令行解析经验
		{
			ExperienceId = FPrimaryAssetId::ParseTypeAndName(ExperienceFromCommandLine); // 解析类型和名称
			if (!ExperienceId.PrimaryAssetType.IsValid()) // 如果主要资源类型无效
			{
				ExperienceId = FPrimaryAssetId(FPrimaryAssetType(ULyraExperienceDefinition::StaticClass()->GetFName()), FName(*ExperienceFromCommandLine)); // 创建经验ID
			}
			ExperienceIdSource = TEXT("CommandLine"); // 设置来源为命令行
		}
	}

	// 查看世界设置是否有默认经验
	if (!ExperienceId.IsValid()) // 如果经验ID无效
	{
		if (ALyraWorldSettings* TypedWorldSettings = Cast<ALyraWorldSettings>(GetWorldSettings())) // 获取Lyra世界设置
		{
			ExperienceId = TypedWorldSettings->GetDefaultGameplayExperience(); // 获取默认游戏玩法经验
			ExperienceIdSource = TEXT("WorldSettings"); // 设置来源为世界设置
		}
	}

	ULyraAssetManager& AssetManager = ULyraAssetManager::Get(); // 获取资源管理器
	FAssetData Dummy; // 虚拟资源数据
	if (ExperienceId.IsValid() && !AssetManager.GetPrimaryAssetData(ExperienceId, /*out*/ Dummy)) // 如果经验ID有效但找不到资源数据
	{
		UE_LOG(LogLyraExperience, Error, TEXT("EXPERIENCE: Wanted to use %s but couldn't find it, falling back to the default)"), *ExperienceId.ToString()); // 记录错误
		ExperienceId = FPrimaryAssetId(); // 清空经验ID
	}

	// 最终回退到默认经验
	if (!ExperienceId.IsValid()) // 如果经验ID无效
	{
		if (TryDedicatedServerLogin()) // 尝试专用服务器登录
		{
			// 这将开始作为专用服务器托管
			return; // 返回
		}

		//@TODO: 从配置设置或其他地方获取这个
		ExperienceId = FPrimaryAssetId(FPrimaryAssetType("LyraExperienceDefinition"), FName("B_LyraDefaultExperience")); // 设置默认经验ID
		ExperienceIdSource = TEXT("Default"); // 设置来源为默认
	}

	OnMatchAssignmentGiven(ExperienceId, ExperienceIdSource); // 调用匹配分配给定回调
}

/**
 * 尝试专用服务器登录
 * @return 是否尝试了专用服务器登录
 */
bool ALyraGameMode::TryDedicatedServerLogin()
{
	// 一些注册为活动专用服务器的基本代码，这将被游戏 heavily 修改
	FString DefaultMap = UGameMapsSettings::GetGameDefaultMap(); // 获取游戏默认地图
	UWorld* World = GetWorld(); // 获取世界
	UGameInstance* GameInstance = GetGameInstance(); // 获取游戏实例
	if (GameInstance && World && World->GetNetMode() == NM_DedicatedServer && World->URL.Map == DefaultMap) // 如果是专用服务器且地图是默认地图
	{
		// 只有在专用服务器上的默认地图时才注册
		UCommonUserSubsystem* UserSubsystem = GameInstance->GetSubsystem<UCommonUserSubsystem>(); // 获取通用用户子系统

		// 专用服务器可能需要在线登录
		UserSubsystem->OnUserInitializeComplete.AddDynamic(this, &ALyraGameMode::OnUserInitializedForDedicatedServer); // 添加用户初始化完成委托

		// 专用服务器上没有本地用户，但索引0意味着默认平台用户，由在线登录代码处理
		if (!UserSubsystem->TryToLoginForOnlinePlay(0)) // 尝试在线播放登录
		{
			OnUserInitializedForDedicatedServer(nullptr, false, FText(), ECommonUserPrivilege::CanPlayOnline, ECommonUserOnlineContext::Default); // 调用用户初始化回调（失败）
		}

		return true; // 返回true
	}

	return false; // 返回false
}

/**
 * 托管专用服务器匹配
 * @param OnlineMode 在线模式
 */
void ALyraGameMode::HostDedicatedServerMatch(ECommonSessionOnlineMode OnlineMode)
{
	FPrimaryAssetType UserExperienceType = ULyraUserFacingExperienceDefinition::StaticClass()->GetFName(); // 用户面向经验定义类型
	
	// 确定要加载的UserFacingExperience
	FPrimaryAssetId UserExperienceId; // 用户经验ID
	FString UserExperienceFromCommandLine; // 命令行用户经验
	if (FParse::Value(FCommandLine::Get(), TEXT("UserExperience="), UserExperienceFromCommandLine) || // 从命令行解析UserExperience
		FParse::Value(FCommandLine::Get(), TEXT("Playlist="), UserExperienceFromCommandLine)) // 或从命令行解析Playlist
	{
		UserExperienceId = FPrimaryAssetId::ParseTypeAndName(UserExperienceFromCommandLine); // 解析类型和名称
		if (!UserExperienceId.PrimaryAssetType.IsValid()) // 如果主要资源类型无效
		{
			UserExperienceId = FPrimaryAssetId(FPrimaryAssetType(UserExperienceType), FName(*UserExperienceFromCommandLine)); // 创建用户经验ID
		}
	}

	// 搜索匹配的经验，在专用服务器启动时强制加载它们是可以的
	ULyraAssetManager& AssetManager = ULyraAssetManager::Get(); // 获取资源管理器
	TSharedPtr<FStreamableHandle> Handle = AssetManager.LoadPrimaryAssetsWithType(UserExperienceType); // 加载主要资源
	if (ensure(Handle.IsValid())) // 确保句柄有效
	{
		Handle->WaitUntilComplete(); // 等待加载完成
	}

	TArray<UObject*> UserExperiences; // 用户经验数组
	AssetManager.GetPrimaryAssetObjectList(UserExperienceType, UserExperiences); // 获取主要资源对象列表
	ULyraUserFacingExperienceDefinition* FoundExperience = nullptr; // 找到的经验
	ULyraUserFacingExperienceDefinition* DefaultExperience = nullptr; // 默认经验

	for (UObject* Object : UserExperiences) // 遍历用户经验
	{
		ULyraUserFacingExperienceDefinition* UserExperience = Cast<ULyraUserFacingExperienceDefinition>(Object); // 转换为用户面向经验定义
		if (ensure(UserExperience)) // 确保转换成功
		{
			if (UserExperience->GetPrimaryAssetId() == UserExperienceId) // 如果找到匹配的经验
			{
				FoundExperience = UserExperience; // 设置找到的经验
				break; // 跳出循环
			}
			
			if (UserExperience->bIsDefaultExperience && DefaultExperience == nullptr) // 如果是默认经验且默认经验为空
			{
				DefaultExperience = UserExperience; // 设置默认经验
			}
		}
	}

	if (FoundExperience == nullptr) // 如果没有找到经验
	{
		FoundExperience = DefaultExperience; // 使用默认经验
	}
	
	UGameInstance* GameInstance = GetGameInstance(); // 获取游戏实例
	if (ensure(FoundExperience && GameInstance)) // 确保找到经验和游戏实例有效
	{
		// 实际托管游戏
		UCommonSession_HostSessionRequest* HostRequest = FoundExperience->CreateHostingRequest(this); // 创建托管请求
		if (ensure(HostRequest)) // 确保托管请求有效
		{
			HostRequest->OnlineMode = OnlineMode; // 设置在线模式

			// TODO 覆盖其他参数？

			UCommonSessionSubsystem* SessionSubsystem = GameInstance->GetSubsystem<UCommonSessionSubsystem>(); // 获取通用会话子系统
			SessionSubsystem->HostSession(nullptr, HostRequest); // 托管会话
			
			// 这将处理地图旅行
		}
	}

}

/**
 * 专用服务器用户初始化回调
 * @param UserInfo 用户信息
 * @param bSuccess 是否成功
 * @param Error 错误信息
 * @param RequestedPrivilege 请求的权限
 * @param OnlineContext 在线上下文
 */
void ALyraGameMode::OnUserInitializedForDedicatedServer(const UCommonUserInfo* UserInfo, bool bSuccess, FText Error, ECommonUserPrivilege RequestedPrivilege, ECommonUserOnlineContext OnlineContext)
{
	UGameInstance* GameInstance = GetGameInstance(); // 获取游戏实例
	if (GameInstance) // 确保游戏实例有效
	{
		// 解绑
		UCommonUserSubsystem* UserSubsystem = GameInstance->GetSubsystem<UCommonUserSubsystem>(); // 获取通用用户子系统
		UserSubsystem->OnUserInitializeComplete.RemoveDynamic(this, &ALyraGameMode::OnUserInitializedForDedicatedServer); // 移除委托

		// 专用服务器不需要用户登录，但一些在线子系统可能期望它
		if (bSuccess && ensure(UserInfo)) // 如果成功且用户信息有效
		{
			UE_LOG(LogLyraExperience, Log, TEXT("Dedicated server user login succeeded for id %s, starting online server"), *UserInfo->GetNetId().ToString()); // 记录日志
		}
		else // 如果失败
		{
			UE_LOG(LogLyraExperience, Log, TEXT("Dedicated server user login unsuccessful, starting online server as login is not required")); // 记录日志
		}
		
		HostDedicatedServerMatch(ECommonSessionOnlineMode::Online); // 托管专用服务器匹配（在线模式）
	}
}

/**
 * 匹配分配给定回调
 * @param ExperienceId 经验ID
 * @param ExperienceIdSource 经验ID来源
 */
void ALyraGameMode::OnMatchAssignmentGiven(FPrimaryAssetId ExperienceId, const FString& ExperienceIdSource)
{
	if (ExperienceId.IsValid()) // 如果经验ID有效
	{
		UE_LOG(LogLyraExperience, Log, TEXT("Identified experience %s (Source: %s)"), *ExperienceId.ToString(), *ExperienceIdSource); // 记录日志

		ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
		check(ExperienceComponent); // 确保组件有效
		ExperienceComponent->SetCurrentExperience(ExperienceId); // 设置当前经验
	}
	else // 如果经验ID无效
	{
		UE_LOG(LogLyraExperience, Error, TEXT("Failed to identify experience, loading screen will stay up forever")); // 记录错误
	}
}

/**
 * 经验加载完成回调
 * @param CurrentExperience 当前经验
 */
void ALyraGameMode::OnExperienceLoaded(const ULyraExperienceDefinition* CurrentExperience)
{
	// 生成任何已附加的玩家
	//@TODO: 这里我们只处理*玩家*控制器，但在GetDefaultPawnClassForController_Implementation中我们跳过了所有控制器
	// GetDefaultPawnClassForController_Implementation可能只对玩家调用
	for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) // 遍历玩家控制器
	{
		APlayerController* PC = Cast<APlayerController>(*Iterator); // 转换为玩家控制器
		if ((PC != nullptr) && (PC->GetPawn() == nullptr)) // 如果控制器有效且没有Pawn
		{
			if (PlayerCanRestart(PC)) // 如果玩家可以重启
			{
				RestartPlayer(PC); // 重启玩家
			}
		}
	}
}

/**
 * 检查经验是否已加载
 * @return 是否已加载
 */
bool ALyraGameMode::IsExperienceLoaded() const
{
	check(GameState); // 确保游戏状态有效
	ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
	check(ExperienceComponent); // 确保组件有效

	return ExperienceComponent->IsExperienceLoaded(); // 返回经验是否已加载
}

/**
 * 获取控制器的默认Pawn类
 * @param InController 控制器
 * @return Pawn类
 */
UClass* ALyraGameMode::GetDefaultPawnClassForController_Implementation(AController* InController)
{
	if (const ULyraPawnData* PawnData = GetPawnDataForController(InController)) // 获取控制器的Pawn数据
	{
		if (PawnData->PawnClass) // 如果Pawn类有效
		{
			return PawnData->PawnClass; // 返回Pawn类
		}
	}

	return Super::GetDefaultPawnClassForController_Implementation(InController); // 调用父类实现
}

/**
 * 在变换处生成默认Pawn
 * @param NewPlayer 新玩家控制器
 * @param SpawnTransform 生成变换
 * @return 生成的Pawn
 */
APawn* ALyraGameMode::SpawnDefaultPawnAtTransform_Implementation(AController* NewPlayer, const FTransform& SpawnTransform)
{
	FActorSpawnParameters SpawnInfo; // 生成参数
	SpawnInfo.Instigator = GetInstigator(); // 设置发起者
	SpawnInfo.ObjectFlags |= RF_Transient;	// 从不将默认玩家Pawn保存到地图中。
	SpawnInfo.bDeferConstruction = true; // 延迟构建

	if (UClass* PawnClass = GetDefaultPawnClassForController(NewPlayer)) // 获取控制器的默认Pawn类
	{
		if (APawn* SpawnedPawn = GetWorld()->SpawnActor<APawn>(PawnClass, SpawnTransform, SpawnInfo)) // 生成Pawn
		{
			if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(SpawnedPawn)) // 查找Pawn扩展组件
			{
				if (const ULyraPawnData* PawnData = GetPawnDataForController(NewPlayer)) // 获取控制器的Pawn数据
				{
					PawnExtComp->SetPawnData(PawnData); // 设置Pawn数据
				}
				else // 如果没有Pawn数据
				{
					UE_LOG(LogLyra, Error, TEXT("Game mode was unable to set PawnData on the spawned pawn [%s]."), *GetNameSafe(SpawnedPawn)); // 记录错误
				}
			}

			SpawnedPawn->FinishSpawning(SpawnTransform); // 完成生成

			return SpawnedPawn; // 返回生成的Pawn
		}
		else // 如果生成失败
		{
			UE_LOG(LogLyra, Error, TEXT("Game mode was unable to spawn Pawn of class [%s] at [%s]."), *GetNameSafe(PawnClass), *SpawnTransform.ToHumanReadableString()); // 记录错误
		}
	}
	else // 如果没有Pawn类
	{
		UE_LOG(LogLyra, Error, TEXT("Game mode was unable to spawn Pawn due to NULL pawn class.")); // 记录错误
	}

	return nullptr; // 返回空
}

/**
 * 是否应在起始点生成
 * @param Player 玩家控制器
 * @return 是否应在起始点生成
 */
bool ALyraGameMode::ShouldSpawnAtStartSpot(AController* Player)
{
	// 我们从不想要使用起始点，总是使用生成管理组件。
	return false; // 返回false
}

/**
 * 处理新玩家开始
 * @param NewPlayer 新玩家控制器
 */
void ALyraGameMode::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer)
{
	// 延迟开始新玩家直到经验加载完成
	//（在此之前登录的玩家将由OnExperienceLoaded启动）
	if (IsExperienceLoaded()) // 如果经验已加载
	{
		Super::HandleStartingNewPlayer_Implementation(NewPlayer); // 调用父类实现
	}
}

/**
 * 选择玩家起始点
 * @param Player 玩家控制器
 * @return 玩家起始点Actor
 */
AActor* ALyraGameMode::ChoosePlayerStart_Implementation(AController* Player)
{
	if (ULyraPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass<ULyraPlayerSpawningManagerComponent>()) // 查找玩家生成管理器组件
	{
		return PlayerSpawningComponent->ChoosePlayerStart(Player); // 使用组件选择玩家起始点
	}
	
	return Super::ChoosePlayerStart_Implementation(Player); // 调用父类实现
}

/**
 * 完成玩家重启
 * @param NewPlayer 新玩家控制器
 * @param StartRotation 起始旋转
 */
void ALyraGameMode::FinishRestartPlayer(AController* NewPlayer, const FRotator& StartRotation)
{
	if (ULyraPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass<ULyraPlayerSpawningManagerComponent>()) // 查找玩家生成管理器组件
	{
		PlayerSpawningComponent->FinishRestartPlayer(NewPlayer, StartRotation); // 使用组件完成玩家重启
	}

	Super::FinishRestartPlayer(NewPlayer, StartRotation); // 调用父类实现
}

/**
 * 玩家是否可以重启
 * @param Player 玩家控制器
 * @return 是否可以重启
 */
bool ALyraGameMode::PlayerCanRestart_Implementation(APlayerController* Player)
{
	return ControllerCanRestart(Player); // 调用控制器是否可以重启
}

/**
 * 控制器是否可以重启
 * @param Controller 控制器
 * @return 是否可以重启
 */
bool ALyraGameMode::ControllerCanRestart(AController* Controller)
{
	if (APlayerController* PC = Cast<APlayerController>(Controller)) // 如果是玩家控制器
	{	
		if (!Super::PlayerCanRestart_Implementation(PC)) // 调用父类玩家是否可以重启
		{
			return false; // 返回false
		}
	}
	else // 如果是机器人控制器
	{
		// Super::PlayerCanRestart_Implementation的机器人版本
		if ((Controller == nullptr) || Controller->IsPendingKillPending()) // 如果控制器无效或待销毁
		{
			return false; // 返回false
		}
	}

	if (ULyraPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass<ULyraPlayerSpawningManagerComponent>()) // 查找玩家生成管理器组件
	{
		return PlayerSpawningComponent->ControllerCanRestart(Controller); // 使用组件检查控制器是否可以重启
	}

	return true; // 返回true
}

/**
 * 初始化游戏状态
 */
void ALyraGameMode::InitGameState()
{
	Super::InitGameState(); // 调用父类

	// 监听经验加载完成	
	ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>(); // 查找经验管理器组件
	check(ExperienceComponent); // 确保组件有效
	ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded)); // 注册经验加载委托
}

/**
 * 通用玩家初始化
 * @param NewPlayer 新玩家控制器
 */
void ALyraGameMode::GenericPlayerInitialization(AController* NewPlayer)
{
	Super::GenericPlayerInitialization(NewPlayer); // 调用父类

	OnGameModePlayerInitialized.Broadcast(this, NewPlayer); // 广播玩家初始化委托
}

/**
 * 请求下一帧重启玩家
 * @param Controller 控制器
 * @param bForceReset 是否强制重置
 */
void ALyraGameMode::RequestPlayerRestartNextFrame(AController* Controller, bool bForceReset)
{
	if (bForceReset && (Controller != nullptr)) // 如果强制重置且控制器有效
	{
		Controller->Reset(); // 重置控制器
	}

	if (APlayerController* PC = Cast<APlayerController>(Controller)) // 如果是玩家控制器
	{
		GetWorldTimerManager().SetTimerForNextTick(PC, &APlayerController::ServerRestartPlayer_Implementation); // 设置下一帧的计时器
	}
	else if (ALyraPlayerBotController* BotController = Cast<ALyraPlayerBotController>(Controller)) // 如果是机器人控制器
	{
		GetWorldTimerManager().SetTimerForNextTick(BotController, &ALyraPlayerBotController::ServerRestartController); // 设置下一帧的计时器
	}
}

/**
 * 更新玩家起始点
 * @param Player 玩家控制器
 * @param Portal 入口
 * @param OutErrorMessage 输出错误消息
 * @return 是否成功
 */
bool ALyraGameMode::UpdatePlayerStartSpot(AController* Player, const FString& Portal, FString& OutErrorMessage)
{
	// 什么都不做，我们将等到PostLogin时尝试真正生成玩家。
	// 现在做任何事情都不好，像团队分配这样的系统甚至还没有发生。
	return true; // 返回true
}

/**
 * 重启玩家失败
 * @param NewPlayer 新玩家控制器
 */
void ALyraGameMode::FailedToRestartPlayer(AController* NewPlayer)
{
	Super::FailedToRestartPlayer(NewPlayer); // 调用父类

	// 如果我们尝试生成Pawn但失败，让我们再试一次 *注意* 检查是否实际有Pawn类
	// 在我们永远尝试之前。
	if (UClass* PawnClass = GetDefaultPawnClassForController(NewPlayer)) // 获取控制器的默认Pawn类
	{
		if (APlayerController* NewPC = Cast<APlayerController>(NewPlayer)) // 如果是玩家控制器
		{
			// 如果是玩家，不要永远循环，也许某些东西改变了，他们不能再重启，如果是这样停止尝试。
			if (PlayerCanRestart(NewPC)) // 如果玩家可以重启
			{
				RequestPlayerRestartNextFrame(NewPlayer, false); // 请求下一帧重启玩家
			}
			else // 如果玩家不能重启
			{
				UE_LOG(LogLyra, Verbose, TEXT("FailedToRestartPlayer(%s) and PlayerCanRestart returned false, so we're not going to try again."), *GetPathNameSafe(NewPlayer)); // 记录详细日志
			}
		}
		else // 如果不是玩家控制器
		{
			RequestPlayerRestartNextFrame(NewPlayer, false); // 请求下一帧重启玩家
		}
	}
	else // 如果没有Pawn类
	{
		UE_LOG(LogLyra, Verbose, TEXT("FailedToRestartPlayer(%s) but there's no pawn class so giving up."), *GetPathNameSafe(NewPlayer)); // 记录详细日志
	}
}